namespace study2_03 {

    // 3.1.定义接口
    // 首先，使用 interface 关键字定义接口。接口可以包含属性和方法的签名，但不包含具体的实现。

    interface Flyable {
        fly(): void

    }
    interface Swimiable {
        swim(): void
    }


    // 3.1.实现接口的类
    // 使用implements关键字让类实现接口，并提供接口中定义的属性和方法的具体实现
    class Brid implements Flyable {
        constructor() {

        }

        fly(): void {
            console.log('鸟儿在飞翔'); // 鸟儿在飞翔

        }
    }

    let bird = new Brid()
    bird.fly()

    // 3.3 一个类实现多个接口
    // 一个类可以通过逗号分隔的方式实现多个接口
    class Duck implements Flyable, Swimiable {
        constructor() {

        }

        fly(): void {
            console.log('鸭子在飞翔'); // 鸭子在飞翔

        }

        swim(): void {
            console.log('鸭子在游泳'); // 鸭子在游泳

        }

    }

    let duck = new Duck()
    duck.fly()
    duck.swim()


    // 3.4 注意事项
    // 必须实现接口中的所有成员：如果一个类实现了某个接口，
    // 那么该类必须实现接口中定义的所有属性和方法。如果未实现，编译器将报错。
    class Fish implements Swimiable {
        constructor() {

        }

        swim(): void {
            console.log('鱼在游泳'); // 鱼在游泳

        }
    }

    let fish = new Fish()
    fish.swim()

    // 接口不能定义具体实现：接口只能定义属性和方法的类型签名，
    // 而不是提供具体的实现。实现接口的时候，具体实现由类来提供。

    // 定义一个可移动的接口
    interface Moveable {
        move(distance: number): void
    }

    class Car implements Moveable {
        // 必须为接口中的方法提供具体实现
        move(distance: number): void {
            console.log(`汽车移动了 ${distance} 米`);

        }
    }




    // 多个接口的实现：当类实现多个接口时，必须实现所有接口中定义的成员。
    // 如果不同接口中有相同的方法签名，类只需要实现一次即可。

    // 定义一个可启动的接口 Startable
    interface Startable {
        start(): void;
    }

    // 定义一个可停止的接口 Stoppable
    interface Stoppable {
        stop(): void
    }

    // 定义一个机械类Machine， 实现 Startable 和 Stoppable 接口
    class Machine implements Startable, Stoppable {
        start(): void {
            console.log('机械启动'); // 机械启动

        }

        stop(): void {
            console.log('机械停止'); // 机械停止

        }
    }

    // 创建一个 Machine类 的实例
    let myMachine: Machine = new Machine()

    myMachine.start()
    myMachine.stop()


    // 接口的继承：接口之间可以继承，一个接口之间可以继承多个接口，继承后的接口可以组合多个接口的成员

    // 定义一个可移动的接口 Moveable2

    interface Moveable2 {
        move(distance: number): void
    }

    interface Drivable extends Moveable2 {
        drive(): void
    }
    class Car2 implements Drivable {
        move(distance: number): void {
            console.log(`汽车移动了 ${distance} m`); // 汽车移动了 200 m

        }

        drive(): void {
            console.log('汽车在行驶'); // 汽车在行驶

        }
    }

    let myCar = new Car2()
    myCar.drive()
    myCar.move(200)

    // 3.5 实际应用示例
    // 下面是一个实际的例子，展示了如何在实际应用中使用接口来定义类，并让类实现多个接口

    // 定义一个可吃的接口
    interface Eatable {
        eat(food: string): void
    }

    // 定义一个可说话的接口
    interface Speakable {
        speak(work: string): void
    }


    // 定义一个人类类，实现 Eatable 和 Speakable 接口
    class Person implements Eatable, Speakable {

        constructor(public name: string) { }
        eat(food: string): void {
            console.log(`${this.name}在吃${food}`);

        }

        speak(work: string): void {
            console.log(`${this.name}在说：${work}`);

        }
    }

    // 创建一个Person类的实例
    let person = new Person('崔梦娇')
    person.eat('榴莲')
    person.speak('榴莲闻着臭吃着香还大补')


    // 关键点总结：
    // 1.接口定义类结构：接口可以定义类的结构，包括属性和方法的签名
    // 2.类实现接口：类使用 implements 关键字实现接口，并提供接口中定义的具体实现
    // 3.实现多个接口：一个类可以实现多个接口，类必须实现所有接口中的成员
    // 4.接口继承：接口可以继承其他接口，组合多个接口的成员

    // 案例练习

    // 1.继承练习
    class Animal5 {
        constructor(public name: string) {
            this.name = name
        }
        move(distance: number = 0) {
            console.log(`${this.name} moved ${distance} m`);

        }
    }

    class Snake5 extends Animal5 {
        constructor(name: string) {
            super(name)
        }

        move(distance: number = 5): void {
            console.log('Slithering...');
            super.move(distance)

        }
    }

    class Horse5 extends Animal5 {
        constructor(name: string) {
            super(name)
        }
        move(distance: number = 45) {
            console.log("Galloping...");
            super.move(distance); // 重写的方法
        }
    }

    let sam = new Snake5('崔梦娇')
    let tom = new Horse5('志超')

    sam.move()
    tom.move(34)


    // 2.公有、私有与受保护的修饰符
    class Person2 {
        public name: string
        private age: number
        protected some: any
        constructor(name: string, age: number, some: any) {
            this.name = name
            this.age = age
            this.some = some
        }

        run() { }

    }

    class Man extends Person2 {
        constructor() {
            super('张三', 18, 1)
            console.log(this.some);

        }

        create() {
            console.log(this.some)
        }
    }

    let xiaoman = new Person2('小曼', 19, 2)
    let man = new Man()
    // man.some // 属性“some”受保护，只能在类“Person2”及其子类中访问
    man.create()




    // 2.静态属性和静态方法
    // 2.1 用static 定义的属性 不可以通过this 去访问 只能通过类名去调用
    // 2.2 static 静态函数 同样也是不能通过this去调用 也是通过类名去调用
    // 2.3 如果两个函数都是static静态的是可以通过this互相调用

    class Person3 {
        public name: string
        private age: number
        protected some: any
        static nb: string

        constructor(name: string, age: number, some: any) {
            this.name = name
            this.age = age
            this.some = some
        }

        static run() {
            return this.aaa() // 如果两个函数都是static 静态的是可以通过this互相调用的
        }

        static aaa() {
            return 'aaa'
        }

    }

    Person3.nb
    Person3.run()
    Person3.aaa()

    // readonly修饰符
    // 你可以使用readonly关键字将属性设置为只读的。只读属性必须在声明时或构造函数里被初始化
    class Octopus {
        readonly name: string
        readonly numberOfLegs: number = 8
        constructor(theName: string) {
            this.name = theName
        }
    }
    let dad = new Octopus('Man with the 8 strong legs')
    // dad.name = 'asodg' // 无法为“name”赋值，因为它是只读属性。


    // ts中的存取器
    // ts支持通过getter/setter来截取对对象成员的访问
    // 它能帮助你有效的控制对对象成员的访问
    let passcode = 'secret passcode';
    class Employee {
        private _fullName: string
        constructor(_fullName: string) {
            this._fullName = _fullName
        }

        get fullName(): string {
            return this._fullName
        }

        set fullName(newName: string) {
            if (passcode && passcode == 'secret passcode') {
                this._fullName = newName
            } else {
                console.log("Error: Unauthorized update of employee!");

            }
        }
    }

    let employee = new Employee('Bob');
    if (employee.fullName) {
        console.log(employee.fullName); // Bob
    }

    // 抽象类
    // 抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。 
    // 不同于接口，抽象类可以包含成员的实现细节。
    //  abstract关键字是用于定义抽象类和在抽象类内部定义抽象方法。
    abstract class Department {
        constructor(public name: string) {

        }

        printName(): void {
            console.log('Department name:' + this.name);

        }

        abstract printMeeting(): void; // 必须在派生类中实现

    }

    class AccountingDepartment extends Department {
        constructor() {
            super('Accounting')
        }
        printMeeting(): void {
            console.log('The Accounting Department meets each Monday at 10am.');

        }
        generateReports(): void {
            console.log('Generating');

        }
    }

    let department: Department; // 允许创建一个对抽象类的引用

    department = new AccountingDepartment(); // 允许对一个抽象子类进行实例化和赋值
    department.printName();
    department.printMeeting();

    // 接口定义类

    // ts中接口interface定义类使用关键字implements，后面跟interface的名字多个用逗号隔开 继承还是用extends

    interface PersonClass {
        get(type: boolean): boolean

    }
    interface PersonClass2 {
        set(): void
        asd: string
    }
    class A {
        name: string
        constructor() {
            this.name = '123'
        }
    }
    class PersonA extends A implements PersonClass, PersonClass2 {
        asd: string
        constructor() {
            super()
            this.asd = '123234'
        }
        get(type: boolean): boolean {
            return type
        }

        set(): void {

        }

    }

    let personA = new PersonA()
    console.log(personA); // PersonA { name: '123', asd: '123234' }









}
